using System;
using System.Collections.Generic;

namespace AutoChess
{ 
    abstract partial class  GameActor
    {
        public ActorActionAttribute Atrr =new ActorActionAttribute();
        
        private List<ActorCmpt> m_listCmpt = new List<ActorCmpt>();
        private Dictionary<string,ActorCmpt> m_mapCmpt = new Dictionary<string, ActorCmpt>();
        private bool m_isDestroyAlling = false;
        public ActorActionAttribute Attr { get; set; }

        private void InitExt()
        {
            m_isDestroyAlling = false;
        }

        #region Component oper function
        public T AddCmpt<T>(bool respawn = true) where T : ActorCmpt, new()
        {
            if (IsDestroyed || m_isDestroyAlling)
            {
                ExLog.LogErrorFormat("Actor is desctroy ,cant add component: {0},IsDestrying [{1}]",GetClassName(typeof(T)),m_isDestroyAlling);
                return null; //是不是考虑空实现？
            }

            T cmpt = GetCmpt<T>();
            if (cmpt != null) return cmpt;

            cmpt = new T();
            if (AddCmpt_Imp(cmpt))
            {
                ExLog.LogErrorFormat("AddComponent failed ,Component name:{0}",GetClassName(typeof(T)));
                cmpt.BeforeDestroy();
                return null;
            }

            return null;
        }
        
        private string GetClassName(Type type)
        {
            return type.FullName;
        }
        
        private T GetCmpt<T>() where T : ActorCmpt, new()
        {
            ActorCmpt cmpt;
            if (m_mapCmpt.TryGetValue(GetClassName(typeof(T)), out cmpt))
            {
                return cmpt as T;
            }

            return null;
        }
        
        private bool AddCmpt_Imp<T>(T cmpt) where T : ActorCmpt, new()
        {
            if (!cmpt.BeforeAddToActor(this))
            {
                return false;
            }

            m_listCmpt.Add(cmpt);
            m_mapCmpt[GetClassName(typeof(T))] = cmpt;
            return true;
        }

        public void RemoveCmpt<T>() where T : ActorCmpt
        {
            if (m_isDestroyAlling)                
            {
                ExLog.LogErrorFormat("GameActor[{0}] is destroying , no need destroy cmpt anyway",GetActorDebugName());
                return;
            }        
                
            string className = GetClassName(typeof(T));
            ActorCmpt cmpt;
            if (m_mapCmpt.TryGetValue(className, out cmpt))
            {
                cmpt.BeforeDestroy();
                Event.RemoveAllListenerByOwner(cmpt);
                m_mapCmpt.Remove(className);
                m_listCmpt.Remove(cmpt);
            }
        }

        public void BeforeDestroyAllCmpt()
        {
            for (int i = 0; i < m_listCmpt.Count; i++)
            {
                m_listCmpt[i].BeforeDestroy();
            }
        }

        public void DestroyAllCmpt()
        {
            m_listCmpt.Clear();
            m_mapCmpt.Clear();
        }
        
        #endregion
        
        #region update cycle

        public void Update()
        {
            if(m_isDestroyAlling)
                return;
            for (int i = 0; i < m_listCmpt.Count; i++)
            {
                var cmpt = m_listCmpt[i];
                cmpt.CallUpdate();
            }
        }
        
        public void LateUpdate()
        {
            if (m_isDestroyAlling)
            {
                return;
            }

            for (int i = 0; i < m_listCmpt.Count; i++)
            {
                var cmpt = m_listCmpt[i];
                cmpt.CallLateUpdate();
            }
        }
        #endregion
       
    }
}